package com.tkjt.pms.calc.core;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.shiro.util.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.tkjt.pms.calc.common.CalcDepartChain;
import com.tkjt.pms.calc.common.DepartOwner;
import com.tkjt.pms.calc.common.IndexCalcSerial;
import com.tkjt.pms.calc.common.IndexTreeConsts;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Transactional
@Service
public class IndexCalcDependecyServiceImpl extends IndexCalcDependecyServiceBase {

	@Override
	public List<IndexCalcSerial> loadIndexCalcDependencies(String dataType, String indexYearMonth, Set<String> indexGroups) {
		List<IndexCalcSerial> results = new ArrayList<IndexCalcSerial>();
		List<String> indexGroupOrders = indexCalcDao.loadIndexGroupOrder(indexGroups);
		for(String indexGroup : indexGroupOrders) {
			
			Set<String> indexDeparts = indexCalcDao.loadDepartLeafs(indexGroup);
			Set<String> indexValueCodes = indexCalcDao.loadIndexValueCodeLeafs(indexGroup);
			
			List<IndexCalcSerial> oneIndexGroupResults = this.loadIndexCalcDependencies(dataType, indexYearMonth, indexGroup, indexValueCodes, indexDeparts);
			
			results.addAll(oneIndexGroupResults);
		}
		return results;
	}

	@Override
	public List<IndexCalcSerial> loadIndexCalcDependencies(String dataType, String indexYearMonth, String indexGroup, Set<String> indexValueCodes, Set<String> indexDeparts) {
		List<IndexCalcSerial> results = new ArrayList<IndexCalcSerial>();

		log.info("start, load depart depen chain..., indexDeparts={}", indexDeparts);
		CalcDepartChain calcDepartChain = this.loadDepartDependencies(dataType, indexYearMonth, indexGroup, indexDeparts);

		Map<Integer, Set<String>> calcIndexValueLevelChain = null;
		calcIndexValueLevelChain = this.loadAndBuildNodeDependencies(IndexTreeConsts.NODE_TYPE_IV_LEVEL, indexYearMonth, indexGroup, indexValueCodes);
		Integer maxdpLevel = calcDepartChain.getLevelSize();
		Integer maxivLevel = calcIndexValueLevelChain.size();
		for (Integer dpLevel = maxdpLevel; dpLevel > 0; dpLevel--) {
			Set<DepartOwner> dplDepartCodes = calcDepartChain.getLevelCodes(dpLevel);
			if (CollectionUtils.isEmpty(dplDepartCodes)) {
				log.error("no depart owner, dpLevel={}", dpLevel);
				continue;
			}
			for (Integer ivLevel = maxivLevel; ivLevel > 0; ivLevel--) {
				Set<String> tempIndexValueCodes = calcIndexValueLevelChain.get(ivLevel);
				IndexCalcSerial oneIndexCalcSerial = this.buildIndexCalcSerial(dataType, indexYearMonth, dplDepartCodes, tempIndexValueCodes);
				results.add(oneIndexCalcSerial);
			}
		}

		log.info("end, load depart depen chain, indexDeparts={}", indexDeparts);
		
		return results;
	}

	@Override
	public List<IndexCalcSerial> loadIndexCalcDependencies(String dataType, String indexYearMonth, String indexGroup, String indexValueCode, String indexDepart) {

		List<IndexCalcSerial> results = new ArrayList<IndexCalcSerial>();

		log.info("start, load depart depen chain..., indexDepart={}", indexDepart);
		Set<String> indexDeparts = new HashSet<String>();
		indexDeparts.add(indexDepart);
		CalcDepartChain calcDepartChain = this.loadDepartDependencies(dataType, indexYearMonth, indexGroup, indexDeparts);

		Map<Integer, Set<String>> calcIndexValueLevelChain = null;
		calcIndexValueLevelChain = this.loadAndBuildNodeDependencies(IndexTreeConsts.NODE_TYPE_IV_LEVEL, indexYearMonth, indexGroup, indexValueCode);
		Integer maxdpLevel = calcDepartChain.getLevelSize();
		Integer maxivLevel = calcIndexValueLevelChain.size();
		for (Integer dpLevel = maxdpLevel; dpLevel > 0; dpLevel--) {
			Set<DepartOwner> dplDepartCodes = calcDepartChain.getLevelCodes(dpLevel);
			if (CollectionUtils.isEmpty(dplDepartCodes)) {
				log.error("no depart owner, dpLevel={}", dpLevel);
				continue;
			}
			for (Integer ivLevel = maxivLevel; ivLevel > 0; ivLevel--) {
				Set<String> indexValueCodes = calcIndexValueLevelChain.get(ivLevel);
				IndexCalcSerial oneIndexCalcSerial = this.buildIndexCalcSerial(dataType, indexYearMonth, dplDepartCodes, indexValueCodes);
				results.add(oneIndexCalcSerial);
			}
		}

		log.info("end, load depart depen chain, indexDepart={}", indexDepart);

		return results;
	}

	private CalcDepartChain loadDepartDependencies(String dataType, String indexYearMonth, String indexGroup, Set<String> indexDeparts) {

		CalcDepartChain chain = new CalcDepartChain();

		Map<Integer, Set<String>> calcDepartDependencies = null;
		calcDepartDependencies = this.loadAndBuildNodeDependencies(IndexTreeConsts.NODE_TYPE_DP_LEVEL, indexYearMonth, indexGroup, indexDeparts);

		Set<Entry<Integer, Set<String>>> entries = calcDepartDependencies.entrySet();
		for (Entry<Integer, Set<String>> entry : entries) {
			indexDeparts.addAll(entry.getValue());
		}

		Map<String, Set<DepartOwner>> departOwers = indexCalcDao.loadDepartOwnersByIndexDeparts(indexDeparts);

		entries = calcDepartDependencies.entrySet();
		for (Entry<Integer, Set<String>> entry : entries) {
			Integer levelKey = entry.getKey();
			Set<String> orgCodes = entry.getValue();
			for (String orgCode : orgCodes) {
				Set<DepartOwner> tempDepartOwners = departOwers.get(orgCode);
				if (CollectionUtils.isEmpty(tempDepartOwners)) {
					log.error("no depart owners, orgCode={}", orgCode);
				} else {
					chain.addLevelCodes(levelKey, tempDepartOwners);
				}
			}
		}

		return chain;
	}


//	private CalcDepartChain loadDepartDependencies(String dataType, String indexYearMonth, String indexGroup, String indexDepart) {
//
//		CalcDepartChain chain = new CalcDepartChain();
//		
//		Set<String> indexDeparts = new HashSet<String>();
//		
//		chain = this.loadDepartDependencies(dataType, indexYearMonth, indexGroup, indexDeparts);
//
//		Map<Integer, Set<String>> calcDepartDependencies = null;
//		calcDepartDependencies = this.loadAndBuildNodeDependencies(IndexTreeConsts.NODE_TYPE_DP_LEVEL, indexYearMonth, indexGroup, indexDepart);
//
//		Set<String> indexDeparts = new HashSet<String>();
//		Set<Entry<Integer, Set<String>>> entries = calcDepartDependencies.entrySet();
//		for (Entry<Integer, Set<String>> entry : entries) {
//			indexDeparts.addAll(entry.getValue());
//		}
//
//		Map<String, Set<DepartOwner>> departOwers = indexCalcDao.loadDepartOwnersByIndexDeparts(indexDeparts);
//
//		entries = calcDepartDependencies.entrySet();
//		for (Entry<Integer, Set<String>> entry : entries) {
//			Integer levelKey = entry.getKey();
//			Set<String> orgCodes = entry.getValue();
//			for (String orgCode : orgCodes) {
//				Set<DepartOwner> tempDepartOwners = departOwers.get(orgCode);
//				if (CollectionUtils.isEmpty(tempDepartOwners)) {
//					log.error("no depart owners, orgCode={}", orgCode);
//				} else {
//					chain.addLevelCodes(levelKey, tempDepartOwners);
//				}
//			}
//		}
//
//		return chain;
//	}

}
